﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using QCloud.CosApi.Api;
using QCloud.CosApi.Common;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace QCloud.CosApi
{
    class Program
    {
        const long SLICE_MIN = 8 * 1024 * 1024;
        const int SLICE_SIZE = 1024 * 1024;
        const int REMOTE_PAGE_SIZE = 1;

        public enum ERROR_CODE
        {
            ERROR_SAME  = -4018,            //相同文件已上传过
            ERROR_CMD_COS_FILE_EXIST = -177,    //文件已存在
        }

        private static List<FileInfo> files = new List<FileInfo>();

        public static void GetFileFromDir(string dir, List<FileInfo> files)
        {
            DirectoryInfo theFolder = new DirectoryInfo(dir);
            DirectoryInfo[] dirInfo = theFolder.GetDirectories();
            //遍历文件夹
            foreach (DirectoryInfo d in dirInfo)
            {
                GetFileFromDir(d.FullName, files);
            }
            FileInfo[] fs = theFolder.GetFiles();
            foreach (FileInfo f in fs)
            {
                files.Add(f);
            }
        }

        public static string UploadFile(CosCloud cos, string bucket, string des, FileInfo file)
        {
            string result = "";
            if (file.Length > SLICE_MIN)
            {
                result = cos.SliceUploadFile(bucket, des, file.FullName, SLICE_SIZE);
            }
            else
            {
                result = cos.UploadFile(bucket, des, file.FullName);
            }
            JObject retJson = JsonConvert.DeserializeObject(result) as JObject;
            int retCode = retJson["code"].ToObject<int>();
            if (retCode != 0)
            {
                if( !HandleError(cos, bucket, retCode, des, file))
                {
                    Console.WriteLine("上传文件失败：" + result);
                }
                return result;
            }
            Console.WriteLine("上传文件成功：" + file.FullName);
            return result;
        }

        public static bool HandleError(CosCloud cos, string bucket, int err, string des, FileInfo file)
        {
            switch (err)
            {
                case (int)ERROR_CODE.ERROR_SAME:
                case (int)ERROR_CODE.ERROR_CMD_COS_FILE_EXIST:
                    cos.DeleteFile(bucket, des);
                    UploadFile(cos, bucket, des, file);
                    return true;
                default:
                    return false;
            }
        }

        private static bool GetRemoteFileByJson(JObject json, ref List<string> files)
        {
            if (json["data"]["filecount"].ToObject<int>() != 0)
            {
                JArray fileArr = json["data"]["infos"] as JArray;
                foreach (JObject file in fileArr)
                {
                    string fileName = file["name"].ToString();
                    files.Add(fileName);
                    Console.WriteLine(string.Format("获取远端文件索引:{0}", fileName));
                }
            }
            return true;
        }

        private static List<string> GetRemoteFile(CosCloud cos, string bucket, string desPath)
        {
            List<string> remoteFiles = new List<string>();
            string ret = cos.GetFolderList(bucket, desPath, REMOTE_PAGE_SIZE, "", 0, FolderPattern.File);
            JObject retJson = JsonConvert.DeserializeObject(ret) as JObject;
            GetRemoteFileByJson(retJson, ref remoteFiles);

            while (retJson["data"]["has_more"].ToObject<bool>())
            {
                string contex = retJson["data"]["context"].ToString();
                ret = cos.GetFolderList(bucket, desPath, REMOTE_PAGE_SIZE, contex, 0, FolderPattern.File);
                retJson = JsonConvert.DeserializeObject(ret) as JObject;
                GetRemoteFileByJson(retJson, ref remoteFiles);
            }
            return remoteFiles;
        }
        public static bool ClearRemotePath(CosCloud cos, string bucket, string desPath)
        {
            List<string> remoteFiles = GetRemoteFile(cos, bucket, desPath);
            foreach (var f in remoteFiles)
            {
                string fullName = desPath + f;
                cos.DeleteFile(bucket, fullName);
                Console.WriteLine(string.Format("删除文件成功：{0}", fullName));
            }
            return true;
        }
        static void Main(string[] args)
        {
            try
            {
                var result = "";
                StreamReader sr = new StreamReader("upload.json");
                JObject cosCfg = JsonConvert.DeserializeObject(sr.ReadToEnd()) as JObject;
                string bucketName = cosCfg["BucketName"].ToString();
                int APP_ID = cosCfg["APP_ID"].ToObject<int>();
                string SECRET_ID = cosCfg["SECRET_ID"].ToString();
                string SECRET_KEY = cosCfg["SECRET_KEY"].ToString();
                string desPath = cosCfg["DesPath"].ToString();
                string localPath = cosCfg["LocalPath"].ToString();
                int command = cosCfg["Command"].ToObject<int>();
                var cos = new CosCloud(APP_ID, SECRET_ID, SECRET_KEY);
                var start = DateTime.Now.ToUnixTime();

                switch (command)
                {
                    case 1:
                        {
                            List<FileInfo> files = new List<FileInfo>();
                            GetFileFromDir(localPath, files);
                            //result = cos.GetFolderList(bucketName, "/", 20, "", 0, FolderPattern.Both);
                            //result = cos.CreateFolder(bucketName, "/sdk/");
                            //result = cos.UploadFile(bucketName, "/sdk/xx.txt", @"D:\aa.txt");
                            //result = cos.UpdateFile(bucketName, "/sdk/xx.txt", "test file");
                            //result = cos.GetFileStat(bucketName, "/sdk/xx.txt");
                            //result = cos.UpdateFolder(bucketName, "/sdk/", "test folder");
                            //result = cos.GetFolderStat(bucketName, "/sdk/");
                            //result = cos.DeleteFile(bucketName, "/sdk/xx.txt");
                            //result = cos.DeleteFolder(bucketName, "/sdk/");


                            foreach (FileInfo f in files)
                            {
                                result = UploadFile(cos, bucketName, desPath + f.Name, f);
                            }
                            Console.WriteLine("成功上传文件到COS");
                            //result = cos.SliceUploadFile(bucketName, "/Res/test.uab", "E:\\Res\\Prefab_Map_YuZhou.prefab.uab", 512 * 1024);
                        }
                        break;
                    case 2:
                        {
                            ClearRemotePath(cos, bucketName, desPath);
                            Console.WriteLine("清空COS成功");
                        }
                        break;
                    default:
                        break;
                }
                var end = DateTime.Now.ToUnixTime();
                Console.WriteLine("总用时：" + (end - start) / 1000.0f + "秒");
                Console.ReadKey();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            Console.ReadKey();
        }
    }
}
